﻿using System.Drawing;
using System.Reflection;
using Admin.ApplicationLib.Services;
using OfficeOpenXml;
using OfficeOpenXml.Style;
using Swimj.CommonLib.Attributes;
using Swimj.CommonLib.Base;
using Swimj.Core.Providers;
using Swimj.Core.Utilities;

namespace Admin.ApplicationLib.Providers
{
    public class EpPlusExcelProvider : IExcelProvider
    {
        public Stream WriteToStream<T>(IList<T> data, string sheetName)
        {
            if (data == null) throw new ArgumentNullException(nameof(data));
            try
            {
                var type = typeof(T);
                var propertyInfos = type.GetProperties();
                var infos = propertyInfos
                    .Where(i => i.IsDefined(typeof(ExcelColumnAttribute), false))
                    .ToList();

                Stream stream = new MemoryStream();


                using (var excelPackage = new ExcelPackage())
                {
                    var worksheet = excelPackage.Workbook.Worksheets.Add(sheetName);

                    IDictionary<string, ExcelColumnAttribute> excelColumnCache =
                        new Dictionary<string, ExcelColumnAttribute>();

                    // Add Header
                    int cellIndex = 1;
                    int rowIndex = 1;
                    foreach (var propertyInfo in infos)
                    {
                        var excelColumnAttribute = propertyInfo.GetCustomAttribute<ExcelColumnAttribute>();
                        if (excelColumnAttribute != null)
                        {
                            excelColumnCache.Add(propertyInfo.Name, excelColumnAttribute);

                            worksheet.Cells[rowIndex, cellIndex].Value =
                                string.IsNullOrEmpty(excelColumnAttribute.DisplayText)
                                    ? propertyInfo.Name
                                    : excelColumnAttribute.DisplayText;
                            var cell = worksheet.Cells[rowIndex, cellIndex];
                            cell.Style.Border.Top.Style = ExcelBorderStyle.Thin;
                            cell.Style.Border.Right.Style = ExcelBorderStyle.Thin;
                            cell.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
                            cell.Style.Border.Left.Style = ExcelBorderStyle.Thin;

                            cell.Style.Fill.PatternType = ExcelFillStyle.Solid;
                            cell.Style.Fill.BackgroundColor.SetColor(Color.Gray);
                            cell.Style.VerticalAlignment = ExcelVerticalAlignment.Center;
                            cell.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;

                            cell.Style.Font.Name = "微软雅黑";
                            cell.Style.Font.Size = 12;
                            cellIndex++;
                        }

                        worksheet.Row(rowIndex).Height = 30;
                    }

                    rowIndex = 2;
                    // Add Content
                    foreach (var item in data)
                    {
                        cellIndex = 1;
                        foreach (var propertyInfo in infos)
                        {
                            ExcelColumnAttribute? excelColumnAttribute = null;

                            if (excelColumnCache.TryGetValue(propertyInfo.Name, out var value))
                            {
                                excelColumnAttribute = value;
                            }

                            var cell = worksheet.Cells[rowIndex, cellIndex];
                            cell.Value = propertyInfo.GetValue(item);

                            if (propertyInfo.PropertyType == typeof(DateTime) ||
                                propertyInfo.PropertyType == typeof(DateTime?))
                            {
                                cell.Style.Numberformat.Format = "yyyy/m/d h:mm";
                            }

                            cell.Style.Font.Name = "微软雅黑";
                            cell.Style.Font.Size = 10;

                            if (excelColumnAttribute != null)
                            {
                                if (!string.IsNullOrEmpty(excelColumnAttribute.Indent))
                                {
                                    cell.Style.Indent =
                                        (int)(type.GetProperty(excelColumnAttribute.Indent)?.GetValue(item) ?? 0) * 2;
                                }
                            }

                            cellIndex++;
                        }

                        worksheet.Row(rowIndex).Height = 20;
                        rowIndex++;
                    }

                    worksheet.Cells.AutoFitColumns(0);
                    excelPackage.SaveAs(stream);
                    stream.Seek(0, SeekOrigin.Begin);
                }

                return stream;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        public Stream WriteToStream<T>(string sheetName)
        {
            try
            {
                var type = typeof(T);
                var propertyInfos = type.GetProperties();
                var infos = propertyInfos
                    .Where(i => i.IsDefined(typeof(ExcelColumnAttribute), false))
                    .ToList();

                Stream stream = new MemoryStream();


                using (var excelPackage = new ExcelPackage())
                {
                    var worksheet = excelPackage.Workbook.Worksheets.Add(sheetName);

                    // Add Header
                    int cellIndex = 1;
                    int rowIndex = 1;
                    foreach (var propertyInfo in infos)
                    {
                        var excelColumnAttribute = propertyInfo.GetCustomAttribute<ExcelColumnAttribute>();
                        if (excelColumnAttribute != null)
                        {
                            worksheet.Cells[rowIndex, cellIndex].Value =
                                string.IsNullOrEmpty(excelColumnAttribute.DisplayText)
                                    ? propertyInfo.Name
                                    : excelColumnAttribute.DisplayText;
                            var cell = worksheet.Cells[rowIndex, cellIndex];
                            cell.Style.Border.Top.Style = ExcelBorderStyle.Thin;
                            cell.Style.Border.Right.Style = ExcelBorderStyle.Thin;
                            cell.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
                            cell.Style.Border.Left.Style = ExcelBorderStyle.Thin;

                            cell.Style.VerticalAlignment = ExcelVerticalAlignment.Center;
                            cell.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;

                            cell.Style.Font.Name = "微软雅黑";
                            cell.Style.Font.Size = 12;
                            if (excelColumnAttribute.Required)
                            {
                                cell.Style.Font.Color.SetColor(Color.Red);
                            }

                            cellIndex++;
                        }

                        worksheet.Row(rowIndex).Height = 30;
                    }

                    worksheet.Cells.AutoFitColumns(0);
                    excelPackage.SaveAs(stream);
                    stream.Seek(0, SeekOrigin.Begin);
                }

                return stream;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        /// <summary>
        /// 读取Excel数据内容，并将其转化为集合
        /// </summary>
        /// <param name="stream"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IList<T> ReadToCollection<T>(Stream stream) where T : ImportTemplateResponseDto
        {
            using (var package = new ExcelPackage(stream))
            {
                ExcelWorksheet worksheet = package.Workbook.Worksheets[0];

                var endRow = worksheet.Dimension.End.Row;
                var endColumn = worksheet.Dimension.End.Column;

                IDictionary<int, PropertyInfo?> propertyDic = new Dictionary<int, PropertyInfo?>();
                var type = typeof(T);
                var propertyInfos = type.GetProperties();

                // 获取对象中需要导入的属性
                var infos = propertyInfos
                    .Where(i => i.IsDefined(typeof(ExcelColumnAttribute), false))
                    .ToList();

                // 读取excel表头，设置对象映射关系
                for (int i = 1; i <= endColumn; i++)
                {
                    var value = worksheet.Cells[1, i].Value;
                    var propertyInfo = infos.FirstOrDefault(p =>
                    {
                        var displayText = p.GetCustomAttribute<ExcelColumnAttribute>()!.DisplayText;
                        if (string.IsNullOrEmpty(displayText))
                        {
                            displayText = p.Name;
                        }

                        return displayText.Equals(value);
                    });
                    propertyDic.Add(i, propertyInfo);
                }

                IList<T> list = new List<T>();
                // 读取excel数据
                for (int i = 2; i <= endRow; i++)
                {
                    // var instance = Activator.CreateInstance<T>();
                    var instance = ReflectionHelper.CreateInstance<T>();
                    instance.Row = i;
                    foreach (var item in propertyDic)
                    {
                        var value = worksheet.Cells[i, item.Key].Value?.ToString();
                        item.Value?.SetValue(instance, value);
                    }

                    list.Add(instance);
                }

                return list;
            }
        }
    }
}